有了前 2 篇從「臺灣證券交易所」取得 CSV 檔後,接著要把資料存入 DB,在存入前,需要先有 DB,本篇以 DB 設計為主
預期會有
Stock)DailyQuote)ExStock)Stock 與 DailyQuote 為一對多關聯Stock 與 ExStock 為一對多關聯class CreateStocks < ActiveRecord::Migration[6.1]
  def change
    create_table :stocks do |t|
      t.string   :name, null: false
      t.string   :code, null: false
      t.datetime :deleted_at
      t.timestamps
    end
    add_index :stocks, :code, unique: true
  end
end
class CreateDailyQuotes < ActiveRecord::Migration[6.1]
  def change
    create_table :daily_quotes do |t|
      t.string  :code, null: false
      t.date    :transaction_date, null: false # 收盤日期
      t.bigint  :trade_volume                  # 成交股數
      t.bigint  :number_of_transactions        # 成交筆數
      t.bigint  :trade_price                   # 成交金額
      t.float   :opening_price                 # 開盤價
      t.float   :highest_price                 # 最高價
      t.float   :lowest_price                  # 最低價
      t.float   :closing_price                 # 收盤價
      t.string  :ups_and_downs                 # 漲跌
      t.float   :price_difference              # 價差
      t.float   :last_best_bid_price           # 最後揭示買價
      t.bigint  :last_best_bid_volume          # 最後揭示買量
      t.float   :last_best_ask_price           # 最後揭示賣價
      t.bigint  :last_best_ask_volume          # 最後揭示賣量
      t.float   :price_earning_ratio           # 本益比
      t.timestamps
    end
    add_index :daily_quotes, %i[code transaction_date], unique: true
  end
end
class CreateExStocks < ActiveRecord::Migration[6.1]
  def change
    create_table :ex_stocks do |t|
      t.string  :code,                        null: false
      t.date    :data_date,                   null: false # 資料日期
      t.float   :closing_price_before,        null: false # 除權息前收盤價
      t.float   :reference_price,             null: false # 除權息參考價
      t.float   :dr_value,                    null: false # 權值+息值
      t.integer :dividend_right,              null: false # 權/息
      t.float   :limit_up,                    null: false # 漲停價格
      t.float   :limit_down,                  null: false # 跌停價格
      t.float   :opening_reference_price,     null: false # 開盤競價基準
      t.float   :ex_dividend_reference_price, null: false # 減除股利參考價
      t.string  :reporting_day                            # 最近一次申報資料 季別/日期
      t.float   :price_book                               # 最近一次申報每股 (單位)淨值
      t.float   :eps                                      # 最近一次申報每股 (單位)盈餘
      t.timestamps
    end
    add_index :ex_stocks, %i[code data_date], unique: true
  end
end
# app/models/stock.rb
class Stock < ApplicationRecord
  validates :name, :code, presence: true
  validates :code, uniqueness: true
  has_many :daily_quotes,               foreign_key: :code, primary_key: :code, dependent: :destroy
  has_many :exs, class_name: "ExStock", foreign_key: :code, primary_key: :code, dependent: :destroy
  
  scope :latest_transaction_date, -> (date = nil) do
    date = date ? date.to_date : DailyQuote.latest_transaction_date
    self.joins(:daily_quotes).where(daily_quotes: { transaction_date: date })
  end
end
# app/models/daily_quote.rb
class DailyQuote < ApplicationRecord
  acts_as_paranoid
  validates :code, :transaction_date, presence: true
  validates :code, uniqueness: { scope: :transaction_date,
    message: "該收盤日期已有紀錄" }
  belongs_to :stock, foreign_key: :code, primary_key: :code
  scope :latest_transaction_date, -> { maximum(:transaction_date) }
end
# app/models/ex_stock.rb
class ExStock < ApplicationRecord
  validates :code, :data_date, :closing_price_before, :reference_price, :dr_value,
            :dividend_right, :limit_up, :limit_down, :opening_reference_price, :ex_dividend_reference_price,
            presence: true
  validates :code, uniqueness: { scope: :data_date, message: "該資料日期已有紀錄" }
  belongs_to :stock, foreign_key: :code, primary_key: :code
  DIVIDEND_RIGHT = {
    "息"   => "xd",
    "權"   => "xr",
    "權息" => "dr",
  }
  enum dividend_right: {
    xd: 0, # 除息 (Exclude Dividend)
    xr: 1, # 除權 (Exclude Right)
    dr: 2, # 除權除息(同時) (DR (Dividend + Right))
  }
  scope :latest_data_date, -> { maximum(:data_date) }
end
設計建立好 DB 後,接下來的兩篇會示範把前兩篇抓下來的資料存到 DB~
鐵人賽文章連結:https://ithelp.ithome.com.tw/articles/10272854
medium 文章連結:https://link.medium.com/s8TWR4KuTjb
本文同步發布於 小菜的 Blog https://riverye.com/
備註:之後文章修改更新,以個人部落格為主